package org.Yiran.timetale_re.recipe;

import com.google.gson.JsonObject;
import net.minecraft.core.RegistryAccess;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
import org.Yiran.timetale_re.Timetale_re;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;
import java.util.function.Consumer;

/**
 * 铁砧锻造配方类
 * 用于定义在铁砧上使用锤子进行锻造的配方
 */
public record AnvilForgeRecipe(ResourceLocation id, ItemStack output, Ingredient input, int inputCount, int hammerLevel,
                               int forgeTime) implements Recipe<Container> {

    /**
     * 检查容器中的物品是否匹配此配方
     * 注意：此配方不使用标准的Container匹配
     *
     * @param container 容器
     * @param level     世界等级
     * @return 总是返回false，因为此配方不使用标准的Container匹配
     */
    @Override
    public boolean matches(@NotNull Container container, @NotNull Level level) {
        return false;
    }

    /**
     * 组装配方结果
     *
     * @param container       容器
     * @param registryAccess  注册表访问器
     * @return 配方的输出物品副本
     */
    @Override
    public @NotNull ItemStack assemble(@NotNull Container container, @NotNull RegistryAccess registryAccess) {
        return this.output.copy();
    }

    /**
     * 检查配方是否可以在指定尺寸的网格中制作
     *
     * @param width  宽度
     * @param height 高度
     * @return 总是返回true
     */
    @Override
    public boolean canCraftInDimensions(int width, int height) {
        return true;
    }

    /**
     * 获取配方结果物品
     *
     * @param registryAccess 注册表访问器
     * @return 配方的输出物品
     */
    @Override
    public @NotNull ItemStack getResultItem(@NotNull RegistryAccess registryAccess) {
        return this.output;
    }

    /**
     * 获取配方ID
     *
     * @return 配方资源位置ID
     */
    @Override
    public @NotNull ResourceLocation getId() {
        return this.id;
    }

    /**
     * 获取配方序列化器
     *
     * @return 配方序列化器
     */
    @Override
    public @NotNull RecipeSerializer<?> getSerializer() {
        return ModRecipes.ANVIL_FORGE_RECIPE_SERIALIZER.get();
    }

    /**
     * 获取配方类型
     *
     * @return 配方类型
     */
    @Override
    public @NotNull RecipeType<?> getType() {
        return ModRecipes.ANVIL_FORGE_RECIPE_TYPE.get();
    }

    /**
     * 检查给定的物品堆是否匹配此配方的输入
     *
     * @param stack 物品堆
     * @return 如果物品堆匹配输入条件则返回true，否则返回false
     */
    public boolean matchesInput(ItemStack stack) {
        return this.input.test(stack) && stack.getCount() >= this.inputCount;
    }

    /**
     * 铁砧锻造配方构建器
     * 用于创建和保存铁砧锻造配方
     */
    public record Builder(ResourceLocation id, ItemStack output, Ingredient input, int inputCount, int hammerLevel,
                          int forgeTime) {

        /**
         * 创建一个新的配方构建器
         *
         * @param name        配方名称
         * @param output      输出物品
         * @param input       输入材料
         * @param inputCount  输入数量
         * @param hammerLevel 锤子等级
         * @param forgeTime   锻造时间（毫秒）
         * @return 新的配方构建器实例
         */
        public static Builder create(String name, ItemStack output, Ingredient input, int inputCount, int hammerLevel, int forgeTime) {
            return new Builder(ResourceLocation.fromNamespaceAndPath(Timetale_re.MODID, name), output, input, inputCount, hammerLevel, forgeTime);
        }

        /**
         * 保存配方（指定名称）
         *
         * @param consumer 配方消费者
         * @param name     配方名称
         */
        public void save(Consumer<FinishedRecipe> consumer, String name) {
            consumer.accept(new Result(ResourceLocation.fromNamespaceAndPath(Timetale_re.MODID, name), output, input, inputCount, hammerLevel, forgeTime));
        }

        /**
         * 保存配方（使用默认ID）
         *
         * @param consumer 配方消费者
         */
        public void save(Consumer<FinishedRecipe> consumer) {
            consumer.accept(new Result(id, output, input, inputCount, hammerLevel, forgeTime));
        }

        /**
         * 配方结果实现类
         * 用于序列化配方数据
         */
        public record Result(ResourceLocation id, ItemStack output, Ingredient input, int inputCount, int hammerLevel,
                             int forgeTime) implements FinishedRecipe {

            /**
             * 序列化配方数据到JSON对象
             *
             * @param json JSON对象
             */
            @Override
            @SuppressWarnings("deprecation")
            public void serializeRecipeData(@NotNull JsonObject json) {
                // 序列化输出物品
                JsonObject outputObject = new JsonObject();
                outputObject.addProperty("item", output.getItem().builtInRegistryHolder().key().location().toString());
                if (output.getCount() > 1) {
                    outputObject.addProperty("count", output.getCount());
                }
                json.add("output", outputObject);

                // 序列化输入材料
                JsonObject inputObject = input.toJson().getAsJsonObject();
                if (inputCount > 1) {
                    inputObject.addProperty("count", inputCount);
                }
                json.add("input", inputObject);

                // 添加锤子等级和锻造时间
                json.addProperty("hammer_level", hammerLevel);
                json.addProperty("forge_time", forgeTime / 1000); // 转换为秒
            }

            /**
             * 获取配方ID
             *
             * @return 配方资源位置ID
             */
            @Override
            public @NotNull ResourceLocation getId() {
                return id;
            }

            /**
             * 获取配方序列化器类型
             *
             * @return 配方序列化器
             */
            @Override
            public @NotNull RecipeSerializer<?> getType() {
                return ModRecipes.ANVIL_FORGE_RECIPE_SERIALIZER.get();
            }

            /**
             * 序列化进度数据
             *
             * @return null，因为此配方不使用进度系统
             */
            @Nullable
            @Override
            public JsonObject serializeAdvancement() {
                return null;
            }

            /**
             * 获取进度ID
             *
             * @return null，因为此配方不使用进度系统
             */
            @Nullable
            @Override
            public ResourceLocation getAdvancementId() {
                return null;
            }
        }
    }

    /**
     * 铁砧锻造配方序列化器
     * 负责配方的序列化和反序列化
     */
    public static class Serializer implements RecipeSerializer<AnvilForgeRecipe> {
        
        /**
         * 从JSON对象中读取配方数据
         *
         * @param recipeId 配方ID
         * @param json     JSON对象
         * @return 铁砧锻造配方实例
         */
        @Override
        public @NotNull AnvilForgeRecipe fromJson(@NotNull ResourceLocation recipeId, @NotNull JsonObject json) {
            // 解析输出物品
            ItemStack output = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "output"));

            // 解析输入材料
            JsonObject inputObject = GsonHelper.getAsJsonObject(json, "input");
            Ingredient input = Ingredient.fromJson(inputObject);
            int inputCount = GsonHelper.getAsInt(inputObject, "count", 1);

            // 解析锤子等级
            int hammerLevel = GsonHelper.getAsInt(json, "hammer_level", 0);

            // 解析锻造时间（秒），默认3秒，并转换为毫秒
            int forgeTime = GsonHelper.getAsInt(json, "forge_time", 3) * 1000;

            return new AnvilForgeRecipe(recipeId, output, input, inputCount, hammerLevel, forgeTime);
        }

        /**
         * 从网络数据包中读取配方数据
         *
         * @param recipeId 配方ID
         * @param buffer   网络数据缓冲区
         * @return 铁砧锻造配方实例
         */
        @Nullable
        @Override
        public AnvilForgeRecipe fromNetwork(@NotNull ResourceLocation recipeId, FriendlyByteBuf buffer) {
            // 从网络数据包读取配方
            ItemStack output = buffer.readItem();
            Ingredient input = Ingredient.fromNetwork(buffer);
            int inputCount = buffer.readVarInt();
            int hammerLevel = buffer.readVarInt();
            int forgeTime = buffer.readVarInt();

            return new AnvilForgeRecipe(recipeId, output, input, inputCount, hammerLevel, forgeTime);
        }

        /**
         * 将配方数据写入网络数据包
         *
         * @param buffer 网络数据缓冲区
         * @param recipe 铁砧锻造配方
         */
        @Override
        public void toNetwork(FriendlyByteBuf buffer, AnvilForgeRecipe recipe) {
            // 将配方写入网络数据包
            buffer.writeItem(recipe.output);
            recipe.input.toNetwork(buffer);
            buffer.writeVarInt(recipe.inputCount);
            buffer.writeVarInt(recipe.hammerLevel);
            buffer.writeVarInt(recipe.forgeTime);
        }
    }
}